home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / MAC / THINKC / 4_0 / VIVIDUS / QD3D.SIT / qd3d / Cqd3dPort.c next >
C/C++ Source or Header  |  1991-10-06  |  24KB  |  1,055 lines

  1. #include    "Cqd3dPort.h"
  2. #include    "Qd3dErr.h"    
  3. #include    <math.h>
  4. #include    <SANE.h>        //    For x80<>x96
  5. #include    <Traps.h>
  6. #include    <TrapTest.h>
  7. #include    <Exceptions.h>
  8.  
  9. /*    ======================================================================
  10.  
  11.     Cqd3dPort primitive three dimensional routine library.
  12.     
  13.     This is part of the qd3d Vividus Source Code Library.  See the
  14.     extern qd3d.doc documentation file for usage.  See individual
  15.     routines for routine documentation.
  16.     
  17.     Copyright 1991 by Vividus Consulting.
  18.     
  19.     This is not public domain source code.  You may not copy and
  20.     paste from this source code.  Read your Vividus Licensing
  21.     agreement for details and other restrictions.
  22.  
  23.     ======================================================================    */
  24.  
  25. Cqd3dPort        *the3dPort;    /*    Present 3d Port set by Set3dPort    */
  26.  
  27. unsigned int    *theZBuff;    /*    ZBuff for the3dPort (if being used)    */
  28. unsigned int    *theZBuffLast;
  29. unsigned int    theZBuffWidth;
  30.  
  31. static
  32. linmap(
  33.     double    a1,
  34.     double    a2,
  35.     double    b1,
  36.     double    b2,
  37.     double    *m,
  38.     double    *b)
  39. /*
  40.     This sets m and b so as to provide a linear mapping from the
  41.     parametric line segment a1->a2 to the line segment b1->b2.
  42.     Use m & b such that:
  43.     
  44.         newparm = m * oldparm + b.
  45.         
  46.     Note that b2 may be < b1 and a2 < a1.  It simply doesn't matter.
  47. */
  48. {
  49.     double    am = a2 - a1;
  50.     double    bm = b2 - b1;
  51.     
  52.     *m = bm / am;
  53.     *b = b1 - a1 * bm / am;
  54. }
  55.  
  56. /*    ============================================================    */
  57. /*    Access methods:                                                    */
  58.  
  59. void Cqd3dPort::Init()
  60. /*
  61.     Initialize this 3dPort to default values.
  62. */
  63. {
  64.     vector    a = {.5, .5, .5};
  65.             
  66.     zbuff = zbufflast = NULL;
  67.     gw = NULL;
  68.     gp = NULL;
  69.     onlyqd = cullbacks = usezbuff = usedepthque = false;
  70.     lastError = noErr;
  71.     onlyqd = true;
  72.     wireframe = false;
  73.     SetPolarView(&a, 10.0, PI/4.0, 60.0 * PI / 180.0, 0.0);
  74. }
  75.  
  76. void Cqd3dPort::Dispose(void)
  77. {
  78.     DisposPtr(this);
  79. }
  80.  
  81. void Cqd3dPort::SetQDEnviron(void)
  82. /*
  83.     Tell this 3dPort to remember its 2d Quickdraw environment.
  84.     
  85.     Remember, call this method just AFTER setting the current QuickDraw
  86.     grafport (with SetPort or SetGWorld) to that which is to contain the
  87.     three dimensional image.  The current Quickdraw port is stored so
  88.     that Set3dPort will automatically call the Quickdraw SetPort() /
  89.     SetGWorld().
  90. */
  91. {
  92.     GDHandle    gd;
  93.     
  94.     gw = NULL;
  95.     gp = NULL;
  96.     
  97.     if (TrapAvailable(_NewGDevice)) {
  98.         GetGWorld(&gw, &gd);
  99.     } else {
  100.         GetPort(&gp);
  101.     }
  102. }
  103.  
  104. void Cqd3dPort::SetQDRect(Rect    *r)
  105. /*
  106.     Tell this 3dPort what portion of its 2d QuickDraw it is to draw on.
  107.     
  108.     This routine does not modify the clipping region.
  109. */
  110. {
  111.     Rect    *vp = &vport;
  112.     long    dimension = (long)(r->right - r->left +1) * (long)(r->bottom - r->top +1);
  113.     
  114.     /*    Set the rectangle    */
  115.     vport.top = r->top;
  116.     vport.left = r->left;
  117.     vport.right = r->right;
  118.     vport.bottom = r->bottom;
  119.     
  120.     /*    Re-assign the zbuffer    */
  121.     zbuffwidth = r->right - r->left + 1;
  122.     if (zbuff)
  123.         DisposPtr(zbuff);
  124.     zbuff = NULL;
  125.     zbufflast = NULL;
  126.     if (usezbuff) {
  127.         zbuff = (unsigned int *)NewPtr( sizeof(unsigned int) * dimension );
  128.         if (!zbuff)
  129.             lastError = noZBuffMem;
  130.         zbufflast = zbuff + dimension;
  131.     }
  132.     
  133.     BuildProj();
  134. }
  135.  
  136. void Cqd3dPort::Erase(void)
  137. /*
  138.     Erase this entire 3dPort.  Including its ZBuff.
  139. */
  140. {
  141.     register unsigned int    *p;
  142.     
  143.     EraseRect(&vport);
  144.     if (zbuff) {
  145.         p = zbuff;
  146.         do {
  147.             *p++ = 0xffff;
  148.         } while (p < zbufflast);
  149.     }
  150. }
  151.  
  152. Cqd3dPort *
  153. Get3dPort(void)
  154. /*
  155.     Returns the current 3dPort.
  156. */
  157. {
  158.     return(the3dPort);
  159. }
  160.  
  161. void Cqd3dPort::Set3dPort(void)
  162. /*
  163.     Tell the 3d library routines, to start drawing to this 3dPort.
  164.     This routine is analogous to Quickdraw's SetPort.
  165.     
  166.     Note:    This routines also set's the current GWorld so that client
  167.             code doesn't have to.
  168. */
  169. {
  170.     if (!(gw || gp))
  171.         Failure(true, SpecifyMsg(Qd3dStr, kNoQDEnviron));
  172.     
  173.     if (gw)
  174.         SetGWorld(gw, NULL);
  175.     if (gp)
  176.         SetPort(gp);
  177.         
  178.     ClipRect(&vport);
  179.     the3dPort = this;
  180.     theZBuff = this->zbuff;
  181.     theZBuffLast = this->zbufflast;
  182.     theZBuffWidth = this->zbuffwidth;
  183. }
  184.  
  185. void Cqd3dPort::BuildTMat(void)
  186. /*
  187.     BuildTMat builds the transformation from world coordinates to
  188.     eye coordinates matrix.
  189.     
  190.     This routine should never be used by client code.
  191. */
  192. {
  193. /*
  194.     The transformation matrix derivation is from:
  195.         "Practical Techniques for Produceing 3D Graphical Images" by
  196.         Thomas A. Foley and Gregory M. Nielson (Computer Science
  197.         Department, Arizona State University) which appeared in VMEbus
  198.         Systems / November-December 1987 pp 65 - 73.  The transformation
  199.         matrix is on pp 68 - 71.
  200. */
  201.     vector    r,
  202.             va,
  203.             vb,
  204.             vc;
  205.  
  206.     vvect(&f, &a, &r);
  207.     vunit(&r, &vc);
  208.     vcopy (&vc, &(tmat[2]));
  209.     
  210.     vcross(&vc, &u, &r);
  211.     vunit(&r, &va);
  212.     vcopy (&va, &(tmat[0]));
  213.     
  214.     vcross(&va, &vc, &vb);
  215.     vcopy(&vb, &(tmat[1]));
  216.  
  217. /*    invert the matrix for matinv    */
  218.  
  219.     /*    This is also a good time for...    */
  220.     vvect(&a, &f, &r);
  221.     vunit(&r, &Ua2f);
  222. }
  223.  
  224. void Cqd3dPort::BuildProj(void)
  225. /*
  226.     BuildProj calculates the projection constants.
  227.     
  228.     This routine should never be used by client code.
  229. */
  230. {
  231. /*
  232.     The perspective projection equations are from:
  233.         "Practical Techniques for Produceing 3D Graphical Images" by
  234.         Thomas A. Foley and Gregory M. Nielson (Computer Science
  235.         Department, Arizona State University) which appeared in VMEbus
  236.         Systems / November-December 1987 pp 65 - 73.  The projection
  237.         equations are on pp 68.
  238. */
  239.     if (type == kqd3dPortPerspective) {
  240.         pwidth = vport.right - vport.left;
  241.         plength = vport.bottom - vport.top;
  242.         pmin = (pwidth < plength) ? pwidth : plength;
  243.         pb = (double)(pmin) / (2.0 * tan(v / 2.0));
  244.         pd = -(double)(pmin) / (2.0 * tan(v / 2.0));
  245.         pa = (vport.right + vport.left)/2;
  246.         pc = (vport.top + vport.bottom)/2;
  247.         
  248.         linmap(zMin, zMax, 0.0, 1.0, &pf, &pe);
  249.     }
  250.     
  251.     if (type == kqd3dPortParallel)    {
  252.         double    aw = ar - al,            /*    The eye coordinate view rectangle.    */
  253.                 ah = at - ab;
  254.         double    bl = vport.left,        /*    The screen viewport rectangle.        */
  255.                 br = vport.right,
  256.                 bt = vport.top,
  257.                 bb = vport.bottom,
  258.                 bw = br - bl,
  259.                 bh = bb - bt;
  260.         double    ayx = ah/aw,
  261.                 byx = bh/bw;
  262.         double    t1, t2;
  263.         
  264.         if (ayx > byx) {
  265.             t1 = bh / ah;
  266.             t2 = t1 * aw;
  267.             bl = (bw - t2) / 2.0 + bl;
  268.             br = bl + t2;
  269.         } else {
  270.             t1 = bw / aw;
  271.             t2 = t1 * ah;
  272.             bt = (bh - t2) / 2.0 + bt;
  273.             bb = bt + t2;
  274.         }
  275.         
  276.         linmap(al, ar, bl, br, &pb, &t1);
  277.         pa = t1;
  278.         linmap(ab, at, bb, bt, &pd, &t1);
  279.         pc = t1;
  280.  
  281.         linmap(zMin, zMax, 0.0, 1.0, &pf, &pe);
  282.     }
  283. }
  284.  
  285. void Cqd3dPort::SetView(
  286.     vector *f,        /*    Viewer location -- WC                */
  287.     vector *a,        /*    Point of attention -- WC            */
  288.     vector *u)        /*    Viewer up vector -- relative to WC    */
  289. /*
  290.     Sets the point of attention, viewer position, and viewer up vector
  291.     for this 3dPort.
  292. */
  293. {
  294.     vcopy(f, &this->f);
  295.     vcopy(a, &this->a);
  296.     vcopy(u, &this->u);
  297.     BuildTMat();
  298.     return;
  299.     
  300.     /*    The following notice may not be removed under any
  301.         circumstance.  See your licensing agreement.        */
  302.     asm {
  303.         dc.b    "qd3d Copyright 1991 Vividus Consulting"
  304.     }
  305. }
  306.  
  307. void Cqd3dPort::GetView(
  308.     vector *f,        /*    Viewer location -- WC                */
  309.     vector *a,        /*    Point of attention -- WC            */
  310.     vector *u)        /*    Viewer up vector -- relative to WC    */
  311. /*
  312.     Returns the point of attention, viewer position, and viewer up vector
  313.     for this 3dPort.
  314. */
  315. {
  316.     vcopy(&this->f, f);
  317.     vcopy(&this->a, a);
  318.     vcopy(&this->u, u);
  319. }
  320.  
  321. int Cqd3dPort::GetProjectionType(void)
  322. /*
  323.     This returns the present type of projection this 3d port performs.
  324. */
  325. {
  326.     return(type);
  327. }
  328.  
  329. void Cqd3dPort::SetPolarView(
  330.     vector *a,        /*    Point of attention -- WC.            */
  331.     double rho,        /*    Distance from a -- WC distance.        */
  332.     double theta,    /*    Theta from WC x direction in an 
  333.                             xy plane.                        */
  334.     double phi,        /*    Phi from WC z direction.            */
  335.     double twist)    /*    Up vector "twist" about a->f axis
  336.                             from "natural" up vector.        */
  337. /*
  338.     Set point of attention, viewer position, and viewer up vector
  339.     for this 3dPort using polar coordianates.  Angle measures
  340.     (theta, phi, and twist) are in radians.
  341. */
  342. {
  343.     vector    f, u;        /*    Calculated viewer postion and up vector    */
  344.     
  345.     /*    Get from location.    */
  346.     vsphere2v (rho, phi, theta, &f);
  347.     vadd(&f, a, &f);
  348.  
  349.     /*    Get up vector.    */
  350.     {
  351.     /*
  352.         Given the current position, center of attention, and user input up
  353.         twist this finds the up vector.
  354.         
  355.         Note:    Yes, this is inefficient... but it should only get called
  356.                 once per rendering (at most).
  357.                 
  358.                 Also, this doesn't take into consideration phi.  Phi isn't
  359.                 necessary because the generation of the transformation
  360.                 matrix doesn't need cv->up to have the phi related component
  361.                 in it.
  362.     */
  363.         vector    v;                    /*    Scratch vectors.                */
  364.         double    p, t,                /*    Phi, theta.                        */
  365.                 st, ct,                /*    Sines and cosines of p, t, & u.    */
  366.                 sp, cp,
  367.                 su, cu;
  368.         double    x, y, z,
  369.                 x1, y1, z1;
  370.         
  371.         vvect(a, &f, &v);
  372.         t = atan2(v.y, v.x);
  373.         t = -t;
  374.         st = sin(t);            ct = cos(t);
  375.         su = sin(twist);        cu = cos(twist);
  376.     #if    0
  377.         p = vangle(&up, &v);
  378.         x = -sp;
  379.         y = 0.0;
  380.         z = cp;
  381.     #else
  382.         x = 0.0;
  383.         y = 0.0;
  384.         z = 1.0;
  385.         
  386.         x1 = x;
  387.         y1 = y*cu + z*su;
  388.         z1 = -y*su + z*cu;
  389.         
  390.         x = x1*ct + y1*st;
  391.         y = -x1*st + y1*ct;
  392.         z = z1;
  393.     
  394.         u.x = x;
  395.         u.y = y;
  396.         u.z = z;
  397.     #endif
  398.     }
  399.  
  400.     SetView(&f, a, &u);
  401. }
  402.  
  403. void Cqd3dPort::GetPolarView(
  404.     vector *a,        /*    Point of attention -- WC.            */
  405.     double *rho,    /*    Distance from a -- WC distance.        */
  406.     double *theta,    /*    Theta from WC x direction in an 
  407.                             xy plane.                        */
  408.     double *phi,    /*    Phi from WC z direction.            */
  409.     double *twist)    /*    Up vector "twist" about a->f axis
  410.                             from "natural" up vector.        */
  411. /*
  412.     Get point of attention, viewer position, and viewer up vector
  413.     for this 3dPort using polar coordianates.  Angle measures
  414.     (theta, phi, and twist) are in radians.
  415.     
  416.     Note:    Presently, this doesn't return the twist angle.
  417. */
  418. {
  419.     vector    v;
  420.     
  421.     vcopy(&this->a, a);
  422.     vsub(&this->f, &this->a, &v);
  423.     vv2sphere(&v, rho, phi, theta);
  424.     
  425.     /*    Get twist angle.    */
  426. *twist = 0.0;
  427. }
  428.  
  429. void Cqd3dPort::SetPerspective(double v, double near, double far)
  430. /*
  431.     Set for perspective projection with the given viewing angle (radians)
  432.     and near and far clippling planes.
  433.     
  434.     Near and far can be considered distances from the eye.
  435.     
  436.     Unity aspect ratio is maintained with the point of attention being
  437.     mapped to the center of the rectangle set with SetGWRect (the 
  438.     viewport).
  439.     
  440.     If the dy/dx ratio's of the window and viewport do not match, the
  441.     entire window specified, plus an extra amount to take up the larger
  442.     viewport area, will be mapped to the viewport.
  443. */
  444. {
  445.     zMin = near;
  446.     zMax = far;
  447.     
  448.     this->v = v;
  449.     
  450.     type = kqd3dPortPerspective;
  451.     
  452.     BuildProj();
  453. }
  454.  
  455. void Cqd3dPort::GetPerspective(double *v, double *near, double *far)
  456. /*
  457.     Get the perspective projection parameters.
  458.     
  459.     Note:    The current projection must be perspective.
  460. */
  461. {
  462.     *near = zMin;
  463.     *far = zMax;
  464.     *v = this->v;
  465. }
  466.  
  467. void Cqd3dPort::SetParallel(
  468.     vector *upperLeft,
  469.     vector *lowerRight,
  470.     double near,
  471.     double far)
  472. /*
  473.     Set for parallel projection with the given eye coordinate rectangle
  474.     defined by upperLeft and lowerRight, and the near and far clipping 
  475.     planes.
  476.     
  477.     Set for perspective projection with the given viewing angle (radians)
  478.     and near and far clippling planes.
  479.     
  480.     Near and far can be considered distances from the eye.
  481.     
  482.     Unity aspect ratio is maintained with the point of attention being
  483.     mapped to the center of the rectangle set with SetGWRect (the 
  484.     viewport).
  485.     
  486.     If the dy/dx ratio's of the window and viewport do not match, the
  487.     entire window specified, plus an extra amount to take up the larger
  488.     viewport area, will be mapped to the viewport.
  489. */
  490. {
  491.     zMin = near;
  492.     zMax = far;
  493.     
  494.     type = kqd3dPortParallel;
  495.     
  496.     al = upperLeft->x;                    /*    The eye coordinate view rectangle.    */
  497.     ar = lowerRight->x;
  498.     at = upperLeft->y;
  499.     ab = lowerRight->y;    
  500.  
  501.     BuildProj();
  502. }
  503.  
  504. void Cqd3dPort::GetParallel(
  505.     vector *upperLeft,
  506.     vector *lowerRight,
  507.     double *near,
  508.     double *far)
  509. /*
  510.     Get the parameters for the parallel projection.
  511.     
  512.     Note:    The current projection must be parallel and the z values of
  513.             the EC upperLeft and lowerRight are meaningless.
  514. */
  515. {
  516.     *near = zMin;
  517.     *far = zMax;
  518.     
  519.     upperLeft->x = al;
  520.     upperLeft->y = at;
  521.     lowerRight->x = ar;
  522.     lowerRight->y = ab;
  523. }
  524.  
  525. int    Cqd3dPort::Qd3dError(void)
  526. /*
  527.     Returns the most recently occured qd3d error.
  528.     
  529.     Note:    That this routine is what resets the last reported qd3d
  530.             and not the called routines!
  531. */
  532. {
  533.     int        retval = lastError;
  534.     
  535.     lastError = noErr;
  536.     return(retval);
  537. }
  538.  
  539. Boolean    Cqd3dPort::GetOnlyQD(void)
  540. /*
  541.     Returns whether the "only quickdraw" flag is set.
  542. */
  543. {
  544.     return(onlyqd);
  545. }
  546.  
  547. void    Cqd3dPort::SetOnlyQD(Boolean onOff)
  548. /*
  549.     Sets the "only quickdraw" flag to onOff.
  550. */
  551. {
  552.     if (onlyqd = onOff)
  553.         if (usezbuff)
  554.             SetUseZBuff(false);
  555. }
  556.  
  557. Boolean    Cqd3dPort::GetCullBacks(void)
  558. /*
  559.     Returns whether backface culling is in affect or not.
  560. */
  561. {
  562.     return(cullbacks);
  563. }
  564.  
  565. void    Cqd3dPort::SetCullBacks(Boolean onOff)
  566. /*
  567.     Sets backface culling to onOff.
  568. */
  569. {
  570.     cullbacks = onOff;
  571. }
  572.  
  573. Boolean    Cqd3dPort::GetUseZBuff(void)
  574. /*
  575.     Returns whether z-buffer hidden surface removal is being used.
  576.     
  577.     Note:    That the "only quicdraw" flag will over-ride zbuffer hidden
  578.             surface removal.
  579. */
  580. {
  581.     return(usezbuff);
  582. }
  583.  
  584. void    Cqd3dPort::SetUseZBuff(Boolean onOff)
  585. /*
  586.     Sets whether z-buffer hidden surface removal will be used.
  587.     
  588.     Note:    The "only quickdraw" flag will over-ride zbuffer hidden
  589.             surface removal.
  590.     
  591.     Note:    For z-buffer hidden surface removal to function properly,
  592.             near and far in SetPerspective or SetParallel must be
  593.             set correctly.
  594. */
  595. {
  596.     if (usezbuff != onOff) {
  597.         usezbuff = onOff;
  598.         SetQDRect(&vport);
  599.     }
  600. }
  601.  
  602. Boolean    Cqd3dPort::GetDepthQue(void)
  603. /*
  604.     Returns whether depth queing is be used during drawing operations.
  605. */
  606. {
  607.     return(usedepthque);
  608. }
  609.  
  610.  
  611. void Cqd3dPort::SetDepthQue(
  612.     Boolean onOff,
  613.     vector *fadeColor,
  614.     double furthestFraction)
  615. /*
  616.     Sets depth queing to onOff.
  617.     
  618.     If onOff is true, fadeColor identifies the color to fade to and
  619.     furthestFraction identifies the amount of fading to be performed
  620.     at points drawn at the far plane.
  621.     
  622.     Ex:    If furthestFraction = 1.0, a point drawn at the far plane will
  623.         be fadeColor.  Points drawn between the far plane and the viewer
  624.         will be a linear blend between the fadeColor and the specified
  625.         drawing color.  The amount of the linear blend is determined
  626.         by how close the point is to the far plane.
  627.  
  628.     Note:    When used in conjunction with "only quickdraw," primitive's
  629.             will be drawn with an average depth qued color.
  630.     
  631.     Note:    For depth queing to function properly, near and far in
  632.             SetPerspective or SetParallel must be set correctly.
  633. */
  634. {
  635.     if (usedepthque = onOff) {
  636.         GetFColor(fadeColor, &dColor);
  637.         
  638. #if    __option(mc68881)
  639.         {
  640.             extended    ext;
  641.     
  642.             x96tox80(&furthestFraction, &ext);
  643.             fFract = X2Fix(ext);
  644.         }
  645. #else
  646.         {
  647.             extended    ext;
  648.             
  649.             x96tox80(&furthestFraction, &ext);
  650.             fFract = X2Fix(ext);
  651.         }
  652. #endif
  653.  
  654.     }
  655. }
  656.  
  657. Boolean Cqd3dPort::GetWireframe(void)
  658. /*
  659.     Returns whether fill operations are drawn using frame operations.
  660. */
  661. {
  662.     return(wireframe);
  663. }
  664.  
  665. void Cqd3dPort::SetWireframe(Boolean onOff)
  666. /*
  667.     Sets Wireframe mode to onOff.  Wireframe mode has the affect
  668.     of maping all fill drawing primitives to frame drawing primitives.
  669. */
  670. {
  671.     wireframe = onOff;
  672. }
  673.  
  674. /*    ============================================================    */
  675. /*    Private transformation/projection primitives:                    */
  676.  
  677. Boolean
  678. Line3dClip(
  679.     vector *p1, vector *p2,        /*    Input segment endpoints.    */
  680.     vector *cp1, vector *cp2    /*    Clipped segment endpoints.    */
  681.                             /*    Above are in eye coordinates.    */
  682. )
  683. /*
  684.     Clip the line segment to the current viewing volume.
  685.     
  686.     If the entire segment is clipped, false is returned.  Otherwise
  687.     true is returned.
  688.     
  689.     Note:    This is not fully implemented.  See below for details.
  690.  
  691.     Warning:    This is a private function to the qd3d library and is
  692.                 highly subject to change or removal.
  693. */
  694. {
  695. /*    
  696.     This is a drastic clipper!  If either point is beyond the near or far
  697.     plane, the entire segment is rejected.
  698.     
  699.     This is an obvious candidate for a more refined implementation.
  700. */
  701.     register Cqd3dPort    *tp = the3dPort;
  702.     
  703.     if ( (p1->z < tp->zMin) || (p2->z < tp->zMin) ||
  704.             (p1->z > tp->zMax) || (p2->z > tp->zMax) )
  705.         return (false);
  706.     vcopy(p1, cp1);
  707.     vcopy(p2, cp2);
  708.     return(true);
  709. }
  710.  
  711. Boolean
  712. LineC3dClip(
  713.     vector *p1, vector *p2,        /*    Input segment endpoints.    */
  714.     vector *cp1, vector *cp2,    /*    Clipped segment endpoints.    */
  715.                             /*    Above are in eye coordinates.    */
  716.     vector *inc1, vector *inc2,    /*    Input endpoint colors.        */
  717.     vector *outc1, vector *outc2/*    Clipped endpoint colors.    */
  718. )
  719. /*
  720.     Clip the line segment to the current viewing volume.  Endpoint
  721.     colors are also appropriately adjusted.
  722.     
  723.     If the entire segment is clipped, false is returned.  Otherwise
  724.     true is returned.
  725.         
  726.     Note:    This is not fully implemented.  See below for details.
  727.  
  728.     Warning:    This is a private function to the qd3d library and is
  729.                 highly subject to change or removal.
  730. */
  731. {
  732. /*    
  733.     This is a drastic clipper!  If either point is beyond the near or far
  734.     plane, the entire segment is rejected.
  735.     
  736.     This is an obvious candidate for a more refined implementation.
  737. */
  738.     register Cqd3dPort    *tp = the3dPort;
  739.     
  740.     if ( (p1->z < tp->zMin) || (p2->z < tp->zMin) ||
  741.             (p1->z > tp->zMax) || (p2->z > tp->zMax) )
  742.         return (false);
  743.     vcopy(p1, cp1);
  744.     vcopy(p2, cp2);
  745.     vcopy(inc1, outc1);
  746.     vcopy(inc2, outc2);
  747.     return(true);
  748. }
  749.  
  750. void
  751. Clip3d(
  752.     int *n,                    /*    Input & output vertice count.    */
  753.     vector inndc[],            /*    Input polygon vertices.            */
  754.     vector outndc[])        /*    Clipped polygon vertices.        */
  755.                         /*    Above are in eye coordinates.        */
  756. /*
  757.     Clip the polygon inndc to the view volume.  Return the clipped
  758.     polygon in outndc and clipped polygon vertex count in n.
  759.  
  760.     Note:    This is not fully implemented.  Se below for details.
  761.  
  762.     Warning:    This is a private function to the qd3d library and is
  763.                 highly subject to change or removal.
  764. */
  765. {
  766. /*    
  767.     This is a drastic clipper!  If any point is beyond the near or far
  768.     plane, the entire point list is ignored (n is set to 0).
  769.     
  770.     This is an obvious candidate for a more refined implementation.
  771. */
  772.     int        i;
  773.     
  774.     for (i = 0; i < *n; i++) {
  775.         if ( (inndc[i].z < the3dPort->zMin) || (inndc[i].z > the3dPort->zMax) ) {
  776.             *n = 0;
  777.             return;
  778.         }
  779.         vcopy(&inndc[i], &outndc[i]);
  780.     }
  781. }
  782.  
  783. void
  784. ClipC3d(
  785.     int *n,                    /*    Input & output vertice count.    */
  786.     vector inndc[],            /*    Input polygon vertices.            */
  787.     vector outndc[],        /*    Clipped polygon vertices.        */
  788.                         /*    Above are in eye coordinates.        */
  789.     vector inc[],            /*    Input vertice colors.            */
  790.     vector outc[]            /*    Output vertice colors.            */
  791. )
  792. /*
  793.     Clip the polygon inndc to the view volume.  Return the clipped
  794.     polygon in outndc and clipped polygon vertex count in n.
  795.     
  796.     Also adjust the vertice colors identified by inc to match the
  797.     clipped polygon.  Return the adjusted colors in outc.
  798.  
  799.     Note:    This is not fully implemented.  Se below for details.
  800.  
  801.     Warning:    This is a private function to the qd3d library and is
  802.                 highly subject to change or removal.
  803. */
  804. {
  805. /*    
  806.     This is a drastic clipper!  If any point is beyond the near or far
  807.     plane, the entire point list is ignored (n is set to 0).
  808.     
  809.     This is an obvious candidate for a more refined implementation.
  810. */
  811.     int        i;
  812.     
  813.     for (i = 0; i < *n; i++) {
  814.         if ( (inndc[i].z < the3dPort->zMin) || (inndc[i].z > the3dPort->zMax) ) {
  815.             *n = 0;
  816.             return;
  817.         }
  818.         vcopy(&inndc[i], &outndc[i]);
  819.         vcopy(&inc[i], &outc[i]);
  820.     }
  821. }
  822.  
  823. static    vector        tndc[PolyMaxN];
  824. static    vector        t2ndc[PolyMaxN];
  825.  
  826. void
  827. TranClipProjf(
  828.     int *n,                    /*    Input & output vertice count.    */
  829.     vector in[],            /*    Input polygon vertices in WC.    */
  830.     FixedVector outdc[])    /*    Clipped vertices in FSC.        */
  831. /*
  832.     Transform, clip and project the polygon vertice list to fixed 
  833.     device screen coordinates.
  834.  
  835.     Warning:    This is a private function to the qd3d library and is
  836.                 highly subject to change or removal.
  837. */
  838. {
  839.     Transform(*n, in, tndc);
  840.     Clip3d(n, tndc, t2ndc);
  841.     Projectf(*n, t2ndc, outdc); 
  842. }
  843.  
  844. void
  845. TranClipProjCf(
  846.     int *n,                    /*    Input & output vertice count.    */
  847.     vector in[],            /*    Input polygon vertices in WC.    */
  848.     FixedVector outdc[],    /*    Clipped vertices in FSC.        */
  849.     vector inc[],            /*    Input vertice colors.            */
  850.     vector outc[])            /*    Output vertice colors.            */
  851. /*
  852.     Transform, clip and project the polygon vertice list to fixed 
  853.     device screen coordinates.
  854.  
  855.     Warning:    This is a private function to the qd3d library and is
  856.                 highly subject to change or removal.
  857. */
  858. {
  859.     Transform(*n, in, tndc);
  860.     ClipC3d(n, tndc, t2ndc, inc, outc);
  861.     Projectf(*n, t2ndc, outdc); 
  862. }
  863.  
  864. void
  865. Projectf(int n, vector xe[], FixedVector xp[])
  866. /*
  867.     Project the eye coordinates in xe to fixed viewport coordinates in xp.
  868.  
  869.     Warning:    This is a private function to the qd3d library and is
  870.                 highly subject to change or removal.
  871. */
  872. {
  873.     int        i;
  874.     vector    v;
  875.     
  876.     for (i = 0; i < n; i++) {
  877.         Project(1, &xe[i], &v);
  878.         ndc2fdc(1, &v, &xp[i]);
  879.     }
  880. }
  881.  
  882. void
  883. ndc2fdc(int n, vector v[], FixedVector fv[])
  884. /*
  885.     Convert the normalized viewport coordinates in v to fixed viewport
  886.     coordinates in fv.
  887.  
  888.     Warning:    This is a private function to the qd3d library and is
  889.                 highly subject to change or removal.
  890. */
  891. {
  892.     int    i;
  893.     
  894.     for (i = 0; i < n; i++) {
  895.         if (v[i].z > 1.0) v[i].z = 1.0;
  896.         if (v[i].z < 0.0) v[i].z = 0.0;
  897.         v[i].z *= 32767.0;
  898.         
  899.         if (v[i].z > 32767)
  900.             Failure(true, SpecifyMsg(Qd3dStr, kZBuffBadScale));
  901.  
  902.         v2fv(&v[i], &fv[i]);
  903.     }
  904. }
  905.  
  906. void
  907. TransformProjectf(int n, vector x[], FixedVector xt[])
  908. /*
  909.     Transform and projects the x world coordinates to fixed viewport
  910.     coordinates.
  911.  
  912.     Warning:    This is a private function to the qd3d library and is
  913.                 highly subject to change or removal.
  914. */
  915. {
  916.     int        i;
  917.     vector    v;
  918.     
  919.     for (i = 0; i < n; i++) {
  920.         Transform(1, &(x[i]), &v);
  921.         Projectf(1, &v, &(xt[i]));
  922.     }
  923. }
  924.  
  925. /*    ============================================================    */
  926. /*    Public transformation/projection primitives:                    */
  927.  
  928. void
  929. Transform(int n, vector x[], vector xt[])
  930. /*
  931.     Transforms the world coordinates in x to eye coordinates in xt.
  932. */
  933. {
  934.     int        i;
  935.     vector    r;
  936.     
  937.     for (i = 0; i < n; i++) {
  938.         vvect(&(the3dPort->f), &(x[i]), &r);
  939.         vmatmul( &r, the3dPort->tmat, &(xt[i]) );
  940.     }
  941. }
  942.  
  943. void
  944. Project(int n, vector xe[], vector xp[])
  945. /*
  946.     Projects the eye coordinates in xe to screen coordinates in xp.
  947.  
  948.     Screen coordinates are actually the GWorld coordinates.
  949. */
  950. {
  951.     register int        i;
  952.     register Cqd3dPort    *p = the3dPort;
  953.     
  954.     if (p->type == kqd3dPortPerspective) {
  955.         for (i = 0; i < n; i++) {
  956.             xp[i].x = p->pa + xe[i].x / xe[i].z * p->pb;
  957.             xp[i].y = p->pc + xe[i].y / xe[i].z * p->pd;
  958.             xp[i].z = p->pe + xe[i].z * p->pf;
  959.     /*        xp[i].z = p->pe * (1.0 - p->zMin / xe[i].z);
  960.     */    }
  961.     } else if (p->type == kqd3dPortParallel) {
  962.         for (i = 0; i < n; i++) {
  963.             xp[i].x = p->pa + xe[i].x * p->pb;
  964.             xp[i].y = p->pc + xe[i].y * p->pd;
  965.             xp[i].z = p->pe + xe[i].z * p->pf;
  966.         }
  967.     }
  968. }
  969.  
  970. void
  971. TransformProject(int n, vector x[], vector xt[])
  972. /*
  973.     Tranform and projects the world coordinates in x to screen
  974.     coordinates in xt.
  975.     
  976.     Screen coordinates are actually the GWorld coordinates.
  977. */
  978. {
  979.     int        i;
  980.     vector    v;
  981.     
  982.     for (i = 0; i < n; i++) {
  983.         Transform(1, &(x[i]), &v);
  984.         Project(1, &v, &(xt[i]));
  985.     }
  986. }
  987.  
  988. void
  989. DepthColor(FixedVector *inc, Fixed z, FixedVector *oc)
  990. /*
  991.     Performs the depth queing color blending function on the input color,
  992.     inc at the z position in screen coordinates (the z buffer value) and
  993.     returns the result in the output color oc.
  994.     
  995.     Note:    If depth queing is off, oc contains inc.
  996. */
  997. {
  998.     Fixed    t;
  999.     FixedVector    fv;
  1000.     
  1001.     if (!the3dPort->usedepthque) {
  1002.         fvcopy(inc, oc);
  1003.         return;
  1004.     }
  1005.     z = z >> 15;
  1006.     t = FixMul(z, the3dPort->fFract);
  1007.     fvscale(t, &the3dPort->dColor, &fv);
  1008.     t = 0x10000 - t;
  1009.     fvscale(t, inc, oc);
  1010.     fvadd(&fv, oc, oc);
  1011. }
  1012.  
  1013. /*    ============================================================    */
  1014.  
  1015. void    Cqd3dPort::DrawOrigin(double size)
  1016. /*
  1017.     Draws the three coordinate axis of the world coordinates using
  1018.     the current fore color.  These axis are labeled.  Size determines
  1019.     how long to make each axis segment and is expressed in world
  1020.     coordinate length.  The labels are drawn at 1.1 times the distance
  1021.     of size.
  1022. */
  1023. {
  1024.     vector    line[2], v;
  1025.     IntVector    iv;
  1026.         
  1027.     line[0].x = 0.0;    line[0].y = 0.0;    line[0].z = 0.0;
  1028.     line[1].x = size;    line[1].y = 0.0;    line[1].z = 0.0;
  1029.     Poly3dLine(2, line);
  1030.     vscale(1.1, &line[1], &line[1]);
  1031.     Qd3dError();
  1032.     MoveTo3d(&line[1]);
  1033.     if (Qd3dError() != moveOutVV)
  1034.         DrawString("\px");
  1035.     
  1036.     line[0].x = 0.0;    line[0].y = 0.0;    line[0].z = 0.0;
  1037.     line[1].x = 0.0;    line[1].y = size;    line[1].z = 0.0;
  1038.     Poly3dLine(2, line);
  1039.     vscale(1.1, &line[1], &line[1]);
  1040.     Qd3dError();
  1041.     MoveTo3d(&line[1]);
  1042.     if (Qd3dError() != moveOutVV)
  1043.         DrawString("\py");
  1044.     
  1045.     line[0].x = 0.0;    line[0].y = 0.0;    line[0].z = 0.0;
  1046.     line[1].x = 0.0;    line[1].y = 0.0;    line[1].z = size;
  1047.     Poly3dLine(2, line);
  1048.     vscale(1.1, &line[1], &line[1]);
  1049.     Qd3dError();
  1050.     MoveTo3d(&line[1]);
  1051.     if (Qd3dError() != moveOutVV)
  1052.         DrawString("\pz");
  1053.     
  1054. }
  1055.